﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections;
using System.Collections.Specialized;
using System.Web.Script.Serialization;

namespace HF.Software.ClassLib
{
    /// <summary>
    /// hef创建于2015.02.03
    /// 用于系统配置文件读写
    /// </summary>
    public class ClsIniFiles
    {
        public string sFileName; //INI文件名

        //声明读写INI文件的API函数
        [DllImport("kernel32")]
        private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath);

        public ClsIniFiles() { }

        //类的构造函数，传递INI文件名
        public ClsIniFiles(string _sFileName)
        {
            // 判断文件是否存在
            FileInfo oFileInfo = new FileInfo(_sFileName);
            //TODO:搞清枚举的用法
            if ((!oFileInfo.Exists))
            { //|| (FileAttributes.Directory in fileInfo.Attributes))
                //文件不存在，建立文件
                System.IO.StreamWriter oSw = new System.IO.StreamWriter(_sFileName, false, System.Text.Encoding.Default);
                try
                {
                    oSw.Write("#表格配置档案");
                    oSw.Close();
                }
                catch
                {
                    throw (new ApplicationException("Ini文件不存在"));
                }
            }
            //必须是完全路径，不能是相对路径
            this.sFileName = oFileInfo.FullName;
        }

        //写INI文件
        public void fnWriteString(string _sSection, string _sIdent, string _sValue)
        {
            if (!WritePrivateProfileString(_sSection, _sIdent, _sValue, this.sFileName))
            {
                throw (new ApplicationException("写Ini文件出错"));
            }
        }

        //读取INI文件指定
        public string fnReadString(string _sSection, string _sIdent, string _sDefault)
        {
            Byte[] bArrBuffer = new Byte[65535];
            int nBufLen = GetPrivateProfileString(_sSection, _sIdent, _sDefault, bArrBuffer, bArrBuffer.GetUpperBound(0), this.sFileName);
            //必须设定0（系统默认的代码页）的编码方式，否则无法支持中文
            string sEncoding = Encoding.GetEncoding(0).GetString(bArrBuffer);
            sEncoding = sEncoding.Substring(0, nBufLen);
            return sEncoding.Trim();
        }

        //读整数
        public int fnReadInteger(string _sSection, string _sIdent, int _nDefault)
        {
            string sStr = this.fnReadString(_sSection, _sIdent, Convert.ToString(_nDefault));
            try
            {
                return Convert.ToInt32(sStr);
            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex.Message);
                return _nDefault;
            }
        }

        //写整数
        public void fnWriteInteger(string _sSection, string _sIdent, int _nValue)
        {
            this.fnWriteString(_sSection, _sIdent, _nValue.ToString());
        }

        //读布尔
        public bool fnReadBool(string _sSection, string _sIdent, bool _bDefault)
        {
            try
            {
                return Convert.ToBoolean(this.fnReadString(_sSection, _sIdent, Convert.ToString(_bDefault)));
            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex.Message);
                return _bDefault;
            }
        }

        //写Bool
        public void fnWriteBool(string _sSection, string _sIdent, bool _bValue)
        {
            fnWriteString(_sSection, _sIdent, Convert.ToString(_bValue));
        }

        //从Ini文件中，将指定的Section名称中的所有Ident添加到列表中
        public void fnReadSection(string _sSection, StringCollection _oIdents)
        {
            Byte[] bArrBuffer = new Byte[16384];
            //Idents.Clear();

            int nBufLen = GetPrivateProfileString(_sSection, null, null, bArrBuffer, bArrBuffer.GetUpperBound(0),
                  this.sFileName);
            //对Section进行解析
            this.fnGetStringsFromBuffer(bArrBuffer, nBufLen, _oIdents);
        }

        #region 序列化配置文件

        /// <summary>
        /// 2015.03.03 hef添加 序列化配置文件
        /// </summary>
        /// <returns></returns>
        public string fnObjToJson()
        {
            try
            {
                AppConfig oAppCfg = new AppConfig();

                JavaScriptSerializer oSerializer = new JavaScriptSerializer();

                string sJson = oSerializer.Serialize(oAppCfg);

                return sJson;
            }
            catch (Exception ex)
            {
                return "";
            }
        }

        #endregion

        private StringCollection fnGetStringsFromBuffer(Byte[] _bArrBuffer, int _nBufLen, StringCollection _oStrings)
        {
            if (null != _oStrings)
                _oStrings.Clear();
            else
                _oStrings = new StringCollection();

            if (_nBufLen != 0)
            {
                int nStart = 0;
                for (int i = 0; i < _nBufLen; i++)
                {
                    if ((_bArrBuffer[i] == 0) && ((i - nStart) > 0))
                    {
                        String sEncoding = Encoding.GetEncoding(0).GetString(_bArrBuffer, nStart, i - nStart);
                        _oStrings.Add(sEncoding);
                        nStart = i + 1;
                    }
                }
            }
            return _oStrings;
        }

        //从Ini文件中，读取所有的Sections的名称
        public StringCollection fnReadSections(StringCollection _oSectionList)
        {
            //Note:必须得用Bytes来实现，StringBuilder只能取到第一个Section
            byte[] bArrBuffer = new byte[65535];
            int nBufLen = 0;
            nBufLen = GetPrivateProfileString(null, null, null, bArrBuffer,
             bArrBuffer.GetUpperBound(0), this.sFileName);
            return this.fnGetStringsFromBuffer(bArrBuffer, nBufLen, _oSectionList);
        }

        //读取指定的Section的所有Value到列表中
        public NameValueCollection fnReadSectionValues(string _sSection, NameValueCollection _oValues)
        {
            StringCollection oKeyList = new StringCollection();
            this.fnReadSection(_sSection, oKeyList);
            _oValues.Clear();
            foreach (string key in oKeyList)
            {
                _oValues.Add(key, this.fnReadString(_sSection, key, ""));
            }

            return _oValues;
        }

        ////读取指定的Section的所有Value到列表中，
        //public void ReadSectionValues(string Section, NameValueCollection Values,char splitString)
        //{　 string sectionValue;
        //　　string[] sectionValueSplit;
        //　　StringCollection KeyList = new StringCollection();
        //　　ReadSection(Section, KeyList);
        //　　Values.Clear();
        //　　foreach (string key in KeyList)
        //　　{
        //　　　　sectionValue=ReadString(Section, key, "");
        //　　　　sectionValueSplit=sectionValue.Split(splitString);
        //　　　　Values.Add(key, sectionValueSplit[0].ToString(),sectionValueSplit[1].ToString());

        //　　}
        //}

        //清除某个Section
        public void fnEraseSection(string _sSection)
        {
            if (!WritePrivateProfileString(_sSection, null, null, this.sFileName))
            {
                throw (new ApplicationException("无法清除Ini文件中的Section"));
            }
        }

        //删除某个Section下的键
        public void fnDeleteKey(string _sSection, string _sIdent)
        {
            WritePrivateProfileString(_sSection, _sIdent, null, this.sFileName);
        }

        //Note:对于Win9X，来说需要实现UpdateFile方法将缓冲中的数据写入文件
        //在Win NT, 2000和XP上，都是直接写文件，没有缓冲，所以，无须实现UpdateFile
        //执行完对Ini文件的修改之后，应该调用本方法更新缓冲区。
        public void fnUpdateFile()
        {
            WritePrivateProfileString(null, null, null, this.sFileName);
        }

        //检查某个Section下的某个键值是否存在
        public bool fnValueExists(string _sSection, string _sIdent)
        {
            StringCollection oIdents = new StringCollection();
            this.fnReadSection(_sSection, oIdents);
            return oIdents.IndexOf(_sIdent) > -1;
        }

        //确保资源的释放
        ~ClsIniFiles()
        {
            this.fnUpdateFile();
        }
    }
}
